home *** CD-ROM | disk | FTP | other *** search
- /*
- sda13.c 06-17-90 (S)uper (D)irectory showing (A)ttributes: Ver. 1.3.
- Slight modification of original program in NSD10A.ZIP by Bob Montgomery.
- * Ver. 1.1 fixed exit foreground color to white from red!
- * Ver. 1.2 expanded the max filenames handled from 500 to 718.
- * Ver. 1.3 06-17-90 warned of too many filenames selected (>718),
- and showed pgm name and version in final line (in place of
- arrows help text) if screen not filled by selected files.
-
- SDA displays a four-up directory listing. With a color CRT, the display
- will present a different color for each file attribute such as ARCHIVE,
- READ-ONLY, READ-WRITE, DIRECTORY, and SYSTEM/HIDDEN.
-
- SDA has been tested under PC DOS 3.3, and 4.0 on a 320 MB hard drive:
- the file count and free space amounts seem to be correct.
-
- If a file size is one meg or larger, SDA shows 999,999 to be able to fit
- four up. If the selected files in a directory total more than 718, SDA
- returns a message rather than an incomplete display as SDA ver. 1.2 did.
-
- If the directory fits on one screen, the last line is the TOTALS line,
- and the SDA version and date appear in the last line in place of text
- concerning use of keypad keys for scrolling.
-
- If the directory overflows one screen, the bottom non-scrollabel line
- is the TOTALS line. The TOTALS line also contains a reminder to use the
- arrow keys (when display overflows one screen), and has the color sceme
- for the file attributes so that you do now have to memorize this screen!
- The TOTALS line also shows a file count and space free.
-
- The main purpose of SDA is to spot files which need backup, are read-only,
- or are system or hidden files.
-
- Colors used in the 4-up DIR display are:
- Directories 12 Lt Red
- Hidden 8 Gray
- System 8 Gray
- Read-only 15 Hi White
- Read-write 10 Hi Green: majority of files
- Archive ON 14 Yellow (for caution, not backed up.)
- This was added to NSD10A original.
- -----------------
- Totals line 11 Hi Cyan 9 Hi Blue etc.
-
-
- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-
- Microsoft `C`, Ver. 5.1 or QuickC 2.0 compile and link batch file:
-
- @ECHO OFF
- Rem CLSDA.BAT 06-17-90 tem
-
- cl SDA13.c /Zp /c
- If errorlevel 1 Echo Error in %0. Link step NOT DONE.
- If errorlevel 1 GOTO @FINIS
-
- Rem DO NOT pack if using stack option...
- Link /STACK:8192 sda13+putstr.obj;
-
- :@FINIS
-
- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-
-
- 08-06-89 Version 1.0 TEM
- SDA fixed an apparant bug: when file count was within a few of a full
- screen, the original program ended scrolling the disply up a line.
- This caused the top line of files to "disappear" from the display.
- Now the escape key must be pressed in such situations before the
- program will end, and the scrolling occurs. This requires a positive
- action by the user.
-
-
- -----------------------------------------------------------------------
-
- Original program intro etc follows:
-
- By Bob Montgomery, Orlando, Fla. CIS [73357,3140] 7-10-88
- SORT.C is a program which reads a directory and prints the files in alph-
- betical order to the screen. It is about as fast as SD, and illustates the
- use of a binary tree to do sorting. It also illustrate other concepts
- useful in writing applications, such as:
- 1. Interfaceing with assy language (putstr.8).
- 2. Accessing C's global varaiables in assy language.
- 3. Using far pointers in a small model program.
- 4. Getting drive parameters.
- 5. Screen management.
- 6. Very fast clear screen.
- 7. Displaying large numbers with commas.
-
- Compile with Microsoft C using the /Zp option to pack structures, and
- then link sort.obj and putstr.obj. If you modify putstr.8 and don't have
- A86, you can add all the 'red tape' required by MASM and assemble
- putstr.8, or better yet, get A86 and assemble with the +cs options to
- make case sensitive. Print at 132 chars/line and 88 lines/page for most
- readable results.
-
- The binary tree has nodes, where each node consists of a string, and a
- left and right pointer to the next node.
-
- The rules for building the tree are:
- 1. Make all left and right pointers null.
- 2. Always start at the root node.
- 3. If the new string is lower (alphabetically) than the string at a node,
- look at the left node; if higher look at the right node.
- 4. If the next node is null, set the pointer (right or left) to the next
- node, and then copy the string to the next node. Otherwise, continue
- the search branching left or right as required.
- The rule for outputing the data alphabetically are:
- 1. Start at the root node.
- 2. Check to the left node. if it is not null, go to it, otherwise output
- the string at this node, and then check the right node. If it is not
- null, go to it, otherwise go to the previous node.
- The output routine is best accomplished using a recursive function (one
- which calls itself). This automatically takes care of the movement up and
- down the tree. Here, that function is untree().
-
- */
-
- #include "stdio.h" /* For printing to screen */
- #include "dos.h" /* For _dos_findfirst and _dos_findnext */
- #include "string.h" /* For string functions */
- #include "process.h" /* For exit function */
- #include "malloc.h" /* For memory allocation */
-
- #define PAGE_UP 73 /* Define command keys */
- #define PAGE_DOWN 81
- #define LEFT_ARROW 75
- #define RIGHT_ARROW 77
- #define UP_ARROW 72
- #define DOWN_ARROW 80
- #define ESC 27
- #define FILEATTR 0x37 /* File attributes; select all but volume labels */
- #define READONLY 1
- #define HIDDEN 2
- #define SYSTEM 4
- #define ARCHIVE 32
- #define SUBDIR 16
-
- struct node /* Define tree node structure */
- { char name[20]; /* Filename and size string */
- int attr; /* File attribute */
- struct node *left, *right; /* Left and right branch pointers */
- } ;
-
- struct fname /* Define filename array */
- { char name[20]; /* Filename and size string */
- int attr; /* File attribute */
- } ;
- struct /* Allocate DTA and define structure */
- { char path[21]; /* DOS path and filespec */
- char attribute; /* File attributes wanted */
- int ftime; /* File creation time */
- int fdate; /* File creation date */
- long size; /* File size in bytes */
- char filename[13]; /* Filename and extension */
- } DTA; /* Disk Transfer Area */
-
- char Nomemmsg[] = "SDA limit of 718 filenames exceeded."; /* Define messages */
- char dir1[] = "*.*";
- char dir2[] = "\\*.*";
- /* */
-
- /************************** Global variables ************************/
-
- /* 1 Blue 2 Green 3 Cyan 4 Red 5 Magenta
- 6 Brown 7 White 8 Gray 9 Lt Blue 10 Lt Green
- 11 Lt Cyan 12 Lt Red 13 Lt Magenta 14 Yellow 15 Lt White
- */
-
- int dirattr = 12; /* Directory entries */
- int hidattr = 8; /* Hidden files */
- int r_oattr = 15; /* Read-only */
- int sysattr = 8; /* System files */
- int arcattr = 14; /* Archive attribute is ON */
- int normattr = 10; /* Normal: files with archive bit OFF */
- int msgattr = 11; /* Totals line */
- int lt_blue = 9; /* Light Blue for program ID */
-
- union REGS regs; /* For DOS and BIOS calls */
- long disksize, dirsize, free_bytes; /* Disk sizes */
- unsigned video_seg; /* Current video display segment */
- int crtrows, crtcols, drive; /* Lines/page, columns/row, and drive */
- int dircount; /* Number of subdirectories found */
-
- char *tempstr; /* Temporary string workfield */
-
- /* Define functions */
- struct fname *untree(struct node *, struct fname *);
- int getfiles(char *, struct fname *);
- void cls();
- void setcursor(int, int);
- void get_drive_data();
- void getdrive();
- void format(char *, long);
- int findfirst(char *);
- int findnext();
-
- /* ======================================================= */
-
-
- main(argc, argv)
- int argc; /* Number of arguments */
- char *argv[]; /* Pointers to arguments */
- { struct fname *dptr; /* Pointer to filename/size structure */
- int count, video_mode; /* Number of files found, current video mode */
- char *dir, *end, *ptr, ch; /* Command line pointers */
- unsigned char far *lowptr; /* Low memory pointer */
-
- if ((dptr = (struct fname *)malloc(32768)) == NULL) /* Allocate memory for array of filenames */
- { puts(Nomemmsg); goto A2; }
-
- /* Parse command line for path:filespec */
- if (argc > 1) /* If a filespec was passed */
- { end = dir = argv[1]; /* Point to it */
- while (*end) end++; /* Find the end of the string */
- end--;
- if ((ch = *end) == ':' || ch == '\\') strcat(dir, dir1); /* If it ends in \ or : add *.* */
- else if ((ptr = strchr(dir, '.')) != NULL) /* else if there is a period */
- { if (ptr == dir) /* If 1st char is a . */
- { if (*(end-1) == '*' && ch == '.') ; /* If last 2 chars are *. do nothing */
- if (ch == '*') ; /* If last char is * do nothing */
- else if (*end == '\\') strcat(dir,dir1); /* If last char is \, add *.* */
- else strcat(dir,dir2); /* else add \*.* */
- } /* Do nothing if filespec */
- }
- else strcat(dir, dir2); /* Otherwise, all files in directory specified */
- }
- else dir = dir1; /* Otherwise, all files in default directory */
- count = getfiles(dir, dptr); /* Get the sorted files to the structure dptr */
- drive = 0; /* Assume default drive */
- if ((ptr = strchr(dir, ':')) != NULL) drive = toupper(*(ptr-1)) - 'A' + 1; /* If drive spec'd */
- FP_SEG(lowptr) = 0; /* Set for low memory */
- FP_OFF(lowptr) = 0x449; /* Get video mode */
- if ((video_mode = *lowptr) >= 0 && video_mode < 4) video_seg = 0xB800; /* Define video segment */
- else if (video_mode == 7) /* If monochrome */
- { video_seg = 0xB000;
- normattr = 7; dirattr = 15; hidattr = msgattr = 0x70; sysattr = 0x88;
- }
- else { printf("%d is a bad Video mode", video_mode); goto A1; }
- FP_OFF(lowptr) = 0x484; /* Get screen rows -1 */
- crtrows = (int)(*lowptr);
- FP_OFF(lowptr) = 0x44A; /* Get columns/row */
- crtcols = (int)(*lowptr);
- if (video_mode == 7) { crtrows = 24; crtcols = 80; } /* Since some mono adapters don't update lower RAM */
- if (count <= 0) puts("No files found"); /* Tell if no files meeting filespec */
- else display(dptr, count); /* else display the files */
-
- A1: free(dptr); /* Free the array buffer */
-
- A2: ; /* Quit to DOS */
-
- }
-
- /* ================================================ */
-
- int getfiles(srchspec, buffer) /* Get and sort all files in path/filespec */
- char *srchspec; /* Path/filespec */
- struct fname *buffer; /* Filename structure to put them in */
- { struct node *entry, *ptr; /* Node structure pointers */
- struct fname *fptr; /* Filename structure pointer */
- int count, errno, i; /* # files and dirs */
- char string[20]; /* Temporary string to hold file data */
-
- if ((entry = (struct node *)malloc(13000)) == NULL) /* Allocate memory for the tree */
- { puts(Nomemmsg);
- return (0);
- }
- for (i=0; i < 720; i++) entry[i].right = entry[i].left = NULL; /* Make all left & right pointers null */
- count = dircount = 0; /* Reset file counters */
- dirsize = 0; /* Reset byte counter */
-
- if (errno = findfirst(srchspec)) goto B; /* If no files found */
-
- ptr = &entry[0]; /* Start at root */
- while (errno == 0) /* While there are files meeting filespec, build the tree */
- { if (DTA.attribute == 16) sprintf(string, "%-12s <DIR>", DTA.filename); /* Was a subdir */
- else /* else was a file */
- { dirsize += DTA.size; /* Add file size to byte counter */
- if (DTA.size > 999999L) DTA.size = 999999L; /* So won't overrun size space */
- sprintf(string, "%-12s %6ld", DTA.filename, DTA.size); /* Copy file data to string */
- }
- if (!count) /* Fill in root entry if count = 0 */
- { strcpy(entry[0].name, string);
- entry[0].attr = DTA.attribute;
- }
- else /* If root filled in */
- { ptr = &entry[0]; /* Start at root */
- while (1) /* Keep going till null pointer found */
- { if ((i = strcmp(string, ptr->name)) < 0) /* If string < name */
- { if (ptr->left == NULL) /* If no pointer yet */
- { ptr = ptr->left = &entry[count]; /* Set pointer to left side & go left */
- break; /* and quit loop */
- }
- else ptr = ptr->left; /* Else go to left */
- }
- else /* If string > name */
- { if (ptr->right == NULL) /* If no pointer to right */
- { ptr = ptr->right = &entry[count]; /* Set pointer to right side & go right */
- break; /* and quit loop */
- }
- else ptr = ptr->right; /* Else go right */
- }
- } /* Try next node till null found */
- strcpy(ptr->name, string); /* Copy name to this node */
- ptr->attr = DTA.attribute;
- }
- if (DTA.attribute == 16) dircount++; /* Inc dir counter if a subdir found */
- count++; /* Inc count */
- if (count == 720) break; /* Limit is 718 files */
- errno = findnext(); /* Find next file */
- } /* Do it again */
- /* Now place the filenames in ascending order in the buffer */
- ptr = &entry[0]; /* Start at root */
- fptr = buffer; /* Point to file buffer */
- untree(ptr, fptr); /* Traverse tree, output to buf */
-
- B: free(entry); /* Free tree memory */
- return (count); /* Return number of files found */
- }
- /* ================================================ */
- struct fname *untree(ptr, fptr) /* Alphabetizes data to fptr */
- struct node *ptr; /* Node structure pointer */
- struct fname *fptr; /* Filename buffer pointer */
- { if (ptr != NULL) /* If not pointing to null */
- { fptr = untree(ptr->left, fptr); /* Go left */
- strcpy(fptr->name, ptr->name); /* Copy name to buffer */
- fptr->attr = ptr->attr; /* and file attribute */
- fptr++; /* Next buffer position */
- fptr = untree(ptr->right, fptr); /* Go right */
- }
- return (fptr); /* Return current buffer pointer */
- }
- /* ============================================ */
- display(dptr, count) /* Display the files */
- struct fname *dptr; /* Data to display */
- int count; /* Number of entries */
- { int start, flag, end, row, col, n, k, nextcol, nextscreen, driveflag;
- int color, columns;
- char line[80], dir[14], disk[14], free[14], ch, *ptr;
-
- start = driveflag = 0; /* Start at 1st file */
- columns = crtcols / 20; /* Get # columns */
- nextscreen = columns * crtrows; /* Get # files for whole screen */
- if (count <= nextscreen) /* If all will go on 1 page */
- { nextcol = count / columns; /* Get number to print/column */
- if (count % columns) nextcol++; /* Inc if not evenly divisible */
- }
- else nextcol = crtrows; /* else use all rows except last */
- flag = ch = 1; /* Fool while statement */
- while (flag || (ch = getch()) != ESC) /* Do until escape pressed */
- { if (ch == 0) ch = getch(); /* Get command */
- switch (ch) /* Adjust start index accordingly */
- { case RIGHT_ARROW:
- if (end < count) start += nextcol; /* If last not shown right 1 column */
- else break;
- flag++;
- break;
- case LEFT_ARROW:
- if (start > 0) /* If not at first */
- { start -= nextcol; /* Left one column */
- if (start < 0) start = 0; /* Adjust */
- }
- else break;
- flag++;
- break;
- case PAGE_UP:
- if (start) /* If start not at first file */
- { if (start >= nextscreen) start -= nextscreen; /* Page back */
- else start = 0; /* or set start = first */
- }
- else break;
- flag++;
- break;
- case PAGE_DOWN:
- if (end != count) /* If not last page */
- { if (end < (count - (columns - 1) * nextcol)) start += nextscreen; /* Page forward */
- else
- { k = count - end; /* Get # files not yet shown */
- n = k / nextcol; /* Get full columns */
- if (k % nextcol) n++; /* Adjust for partial columns */
- start += n * nextcol; /* Set new start index */
- }
- }
- else break;
- flag++;
- break;
- case UP_ARROW:
- if (start > 0) /* If not at start */
- { start--; /* Previous file */
- flag++;
- }
- break;
- case DOWN_ARROW:
- if (end < count) /* If not at end */
- { start++; /* Next file */
- flag++;
- }
- }
- if (flag) /* If start index changed */
- { end = start + nextscreen; /* Compute end index */
- if (end > count) end = count;
- cls(); /* Clear the screen */
- for (row=0; row < nextcol; row++) /* Do all rows */
- { for (col=0; col < columns; col++) /* Do all columns */
- { n = start + nextcol * col + row; /* Get index */
- if (n >= count) break; /* Stop if last one */
- if (col < (columns - 1)) k = 1; else k = 0; /* File divider logic */
- if (dptr[n].attr & HIDDEN) color = hidattr; /* Set attributes */
- else if (dptr[n].attr & SYSTEM) color = sysattr;
- else if (dptr[n].attr & READONLY) color = r_oattr;
- else if (dptr[n].attr & ARCHIVE) color = arcattr;
- else if (dptr[n].attr & SUBDIR) color = dirattr;
- else color = normattr;
- putstring(row, 20 * col, color, dptr[n].name, 0); /* Print to display */
- }
- }
- /* */
- if (!driveflag) /* If we haven't got drive data yet */
- { get_drive_data(); /* Get the drive data */
- format(dir, dirsize); /* Format sizes with commas */
- format(disk, disksize);
- format(free, free_bytes);
- driveflag++; /* Don't do again */
- }
-
- sprintf(line, "%d files %s free ",
- (count - dircount), free);
- putstring(nextcol, 0, msgattr, line, 0);
-
- if ((count - dircount) - 718 == 0)
- { cls();
- sprintf(line, " Number of filenames selected was greater than 717 SDA maximum. ");
- putstring(nextcol, 3, dirattr, line, 0);
- exit(1);
- }
-
- sprintf(line, " SDA Ver 1.3 06/90 "); /* If all fits on*/
- putstring(nextcol, 29, lt_blue, line, 0); /* just 1 screen */
-
- if ((count - dircount) - 94 > 0)
- {
- sprintf(line, "PgUp/Dn/Arrow/Esc. "); /* More than one */
- putstring(nextcol, 30, lt_blue, line, 0); /* screen worth..*/
- }
-
- tempstr = "Attr: ";
- putstring(nextcol, 50, msgattr, tempstr, 0);
-
- tempstr = "Dir ";
- putstring(nextcol, 56, dirattr, tempstr, 0);
-
- tempstr = "Sys/Hid ";
- putstring(nextcol, 60, sysattr, tempstr, 0);
-
- tempstr = "R-O ";
- putstring(nextcol, 68, r_oattr, tempstr, 0);
-
- tempstr = "Arc ";
- putstring(nextcol, 72, arcattr, tempstr, 0);
-
- tempstr = "R-W ";
- putstring(nextcol, 76, normattr, tempstr, 0);
-
- flag = 0; /* Clear the command flag */
- }
- if (count < (nextscreen - columns)) break; /* Quit if screen not full */
- }
- setcursor(nextcol, 0); /* Set cursor for DOS exit */
-
- /* printf("count = %d nextscreen = %d", count, nextscreen); */ /* Debug */
- /* printf("columns = %d crtrows = %d", columns, crtrows); */ /* Debug */
-
-
- }
-
- /* =========================================== */
- void cls() /* Clears the screen on the spec'd page */
- { setcursor(0, 0);
- regs.x.ax = 0x920; /* Write char & attr-char = space */
- regs.x.bx = 6; /* Page 0, color 6 */
- regs.x.cx = crtrows * crtcols; /* Whole screen to write */
- int86(0x10, ®s, ®s);
- }
-
- /* ========================================== */
- void setcursor(row, col) /* Set cursor to row, col thru BIOS */
- int row, col;
- { regs.h.ah = 2; /* BIOS set cursor function */
- regs.h.bh = 0; /* Page 0 */
- regs.h.dh = row;
- regs.h.dl = col;
- int86(0x10,®s,®s);
- }
- /* ========================================== */
- void get_drive_data() /* Gets data for drive */
- { int sectors_per_cluster, bytes_per_sector;
- unsigned total_clusters, free_clusters;
- int bytes_per_cluster, dir_clusters;
-
- regs.h.ah = 0x36; /* Get disk parameters */
- regs.h.dl = drive; /* 0=default, 1=A, etc */
- intdos(®s, ®s);
- total_clusters = regs.x.dx; /* Get data */
- free_clusters = regs.x.bx;
- sectors_per_cluster = regs.x.ax;
- bytes_per_sector = regs.x.cx;
- bytes_per_cluster = sectors_per_cluster * bytes_per_sector; /* Compute some more data */
- disksize = (long)bytes_per_cluster * (long)total_clusters;
- free_bytes = (long)bytes_per_cluster * (long)free_clusters;
- }
- /* ================================================ */
- void format(ptr, size) /* Format the long number size to string ptr using commas */
- char *ptr;
- long size;
- { int mil, tho, ones;
- char *tmp, fmt[6];
-
- mil = (int)(size / 1000000L); /* Get millions */
- tho = (int)((size - 1000000L * (long)mil) / 1000); /* Get thousands */
- ones = size % 1000; /* Get ones */
- *(tmp = ptr) = 0; /* Point to output string */
- if (mil) sprintf(tmp, "%d,", mil); /* If millions, print them and comma */
- while (*tmp) tmp++; /* Find end of millions */
- if (mil) sprintf(tmp, "%03d,", tho); /* If millions, print 3 digits for thousands & comma */
- else if (tho) sprintf(tmp, "%3d,", tho); /* else if tousands, print them and comma */
- while (*tmp) tmp++; /* Find end of thousands */
- if (mil || tho) sprintf(tmp, "%03d", ones); /* If millions or thousands, print ones */
- else sprintf(tmp, "%3d", ones); /* else print ones */
- }
- /* ===================================================== */
- int findfirst(path) /* Find 1st file (or subdir) meeting path/filespec */
- char *path; /* DOS path/filespec */
- { regs.h.ah = 0x1A; /* Set DTA to filedata */
- regs.x.dx = (unsigned)&DTA;
- intdos(®s, ®s);
- regs.h.ah = 0x4E; /* Find 1st file meeting path */
- regs.x.dx = (unsigned)path;
- regs.x.cx = FILEATTR;
- intdos(®s, ®s);
- return(regs.x.ax); /* Return error code */
- }
- /* ===================================================== */
- int findnext() /* Find next file (or subdir) meeting above path/filespec */
- { regs.h.ah = 0x4F; /* Find next file meeting path */
- regs.x.dx = (unsigned)&DTA;
- intdos(®s, ®s);
- return(regs.x.ax);
- }
-